package com.gofaraway.common.util;

import com.alibaba.fastjson.JSON;
import com.gofaraway.common.exception.v2.BusinessException;
import com.gofaraway.common.exception.v2.CommonErrorConstants;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author ChenPeng
 * @Date 2024/7/24 16:35
 */
public class RequestUtils {

    private RequestUtils() {
        throw new UnsupportedOperationException("静态工具类不允许被实例化");
    }

    private static final String X_FORWARDED_FOR = "X-forwarded-for";
    private static final String PROXY_CLIENT_IP = "Proxy-Client-IP";
    private static final String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
    private static final String HTTP_CLIENT_IP = "HTTP_CLIENT_IP";
    private static final String UNKNOWN = "unknown";
    private static final String HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR";
    private static final String COMMA = ",";

    private static final Pattern INNER_IP_REG = Pattern.compile("^(127\\.0\\.0\\.1)|(localhost)|(10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(172\\.((1[6-9])|(2\\d)|(3[01]))\\.\\d{1,3}\\.\\d{1,3})|(192\\.168\\.\\d{1,3}\\.\\d{1,3})$");

    /**
     * 检查是否内网ip
     */
    public static boolean isInnerIp(String ip) {
        Matcher match = INNER_IP_REG.matcher(ip);
        return match.find();
    }

    /**
     * 检查这个请求是否内网发起的，即来源ip是否内网地址
     */
    public static boolean isInnerRequest(HttpServletRequest request) {
        String ip = getIpAddress(request);
        if (org.apache.commons.lang3.StringUtils.isBlank(ip)) {
            return false;
        }
        return INNER_IP_REG.matcher(ip).find();
    }

    /**
     * 从 request 中获取请求来源真实地址
     *
     * @param request 当前请求
     * @return 真实来源地址
     */
    public static String getIpAddress(HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        String ip = request.getHeader(X_FORWARDED_FOR);
        if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(PROXY_CLIENT_IP);
        }
        if (ip == null || ip.isEmpty() || RequestUtils.UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(WL_PROXY_CLIENT_IP);
        }
        if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HTTP_CLIENT_IP);
        }
        if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader(HTTP_X_FORWARDED_FOR);
        }
        if (ip == null || ip.isEmpty() || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip != null && ip.contains(COMMA)) {
            // 对于通过多个代理的情况，取第一个非 unknown 的有效IP字符串
            String[] ips = ip.split(COMMA);
            for (String s : ips) {
                if (!UNKNOWN.equalsIgnoreCase(s)) {
                    ip = s;
                    break;
                }
            }
        }
        return ip;
    }

    /**
     * 获取完整的请求路径, 包含 queryString
     *
     * @param request 当前请求
     * @return 完整的请求路径
     */
    public static String getFullRequestUrl(HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(request.getQueryString())) {
            return request.getRequestURL().toString();
        }
        return request.getRequestURL().append('?').append(request.getQueryString()).toString();
    }

    /**
     * 获取完整的请求路径, 包含 queryString
     *
     * @param requestUrl  请求url
     * @param queryString 请求参数
     * @return 完整请求路径
     */
    public static String getFullRequestUrl(String requestUrl, String queryString) {
        if (org.apache.commons.lang3.StringUtils.isBlank(queryString) && org.apache.commons.lang3.StringUtils.isBlank(requestUrl)) {
            return "";
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(queryString)) {
            return requestUrl;
        }
        return requestUrl + "?" + queryString;
    }

    /**
     * 检查是否LINK请求，若是则反序列化结果，否则直接抛出业务异常
     *
     * @return 将请求体反序列化后的结果
     */
    public static <T> T checkIsLinkRequestAndGetContent(HttpServletRequest request, Class<T> clz) {
        checkIsLinkRequest(request);
        String content = request.getParameter("content");
        if (org.apache.commons.lang3.StringUtils.isBlank(content)) {
            return null;
        }
        return JSON.parseObject(content, clz);
    }

    /**
     * 检查是不是来自 LINK 的请求，即 是否内网发起的请求，是否有 from_appkey，如果不是则直接抛出业务异常
     */
    public static void checkIsLinkRequest(HttpServletRequest request) {
        // 检查是否内网，LINK接口仅限内网调用
        boolean isInnerRequest = RequestUtils.isInnerRequest(request);
        if (!isInnerRequest) {
            throw BusinessException.of(CommonErrorConstants.BIZ_OPERATE_FORBIDDEN).withPlaceHolderParam(", 非法请求，本接口仅限内部调用");
        }
        String fromAppKey = request.getParameter("from_appkey");
        if (org.apache.commons.lang3.StringUtils.isBlank(fromAppKey)) {
            throw BusinessException.of(CommonErrorConstants.BIZ_OPERATE_FORBIDDEN).withPlaceHolderParam(", 非法请求，来源不明");
        }
    }

    /**
     * 从 request 中获取当前用户凭证
     *
     * @param request 当前请求
     * @return 用户凭证
     */
    public static String getUserPrincipal(HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        Principal principal = request.getUserPrincipal();
        if (principal != null && StringUtils.isNotBlank(principal.getName())) {
            return principal.getName();
        }
        return "";
    }
}
